<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/**
 * Themes class
 * 
 * This class is used for themeing and templating pages. It allows master pages, content blocks, and auto page fetching based on uri.
 * 
 * @package Themes
 * @version 0.3b
 * @author chadwithuhc
 * @link http://chadwithuhc.com
 * @copyright 2009 chadwithuhc
 * 
 */
class Themes {

	var $ci;

	/**
	 * $theme
	 * 
	 * The default theme to use
	 * 
	 * (default value: 'default')
	 * 
	 * @var string
	 * @access public
	 */
	var $theme = 'default';

	/**
	 * $master
	 * 
	 * The default master template
	 * 
	 * (default value: 'main.master')
	 * 
	 * @var string
	 * @access public
	 */
	var $master = 'main.master';

	 /**
	 * $page
	 * 
	 * The default page to be loaded
	 * Note: if you set this other than null, page will NEVER be auto loaded by uri
	 * 
	 * (default value: null)
	 * 
	 * @var string
	 * @access public
	 */
	var $page = null;
	
	/**
	 * $sep
	 * 
	 * The default separator. / is for folders.
	 * 
	 * (default value: '/')
	 * 
	 * @var string
	 * @access public
	 */
	var $sep = '/';
	
	/**
	 * $views_root
	 * 
	 * The root location of views folder if you are not using the standard APPPATH / views folder
	 * 
	 * (default value: APPPATH)
	 * 
	 * @var string
	 * @access public
	 */
	var $views_root = APPPATH;
	
	/**
	 * $themes_root
	 * 
	 * The root location of themes folder.
	 * 
	 * (default value: APPPATH)
	 * 
	 * @var string
	 * @access public
	 */
	var $themes_root = APPPATH;
	
	/**
	 * $folders
	 * 
	 * The default folder names.
	 * 
	 * @var array
	 * @access public
	 */
	var $folders = array(
		'themes' => 'themes',
		'css' => 'styles',
		'images' => 'images',
		'javascript' => 'js',
		'views' => 'views',
		'blocks' => 'content-blocks',
		'masters' => 'masters',
		'pages' => 'pages'
	);
	
	/**
	 * $admin_theme
	 * 
	 * The default theme settings for admin. Used in $this->admin(). Overwrites $folders when used.
	 * 
	 * @var array
	 * @access public
	 */
	var $admin_theme = array(
		'theme' => 'admin',
		'master' => 'admin.master',
	);

	/**
	 * $content_tag
	 * 
	 * Used to output content from masters. Gets encrypted with sha1() to prevent duplicate replacements.
	 * 
	 * (default value: '{content}')
	 * 
	 * @var string
	 * @access public
	 */
	var $content_tag = '{content}';

	/**
	 * Themes ()
	 * 
	 * Default constructor. Gets CI instance and sets roots.
	 * 
	 * @access public
	 * @return void
	 */
	function Themes() {
		$this->ci =& get_instance();
		$this->set_views_root($this->views_root);
		$this->set_themes_root($this->themes_root);
	}

	/**
	 * admin ( $page = null, $values = null )
	 * 
	 * Declares admin theme settings based on $amin_theme or passed in array
	 * 
	 * @access public
	 * @param string $page (default: null) page path
	 * @param array $values (default: null) admin values that will override defaults
	 * @return Themes
	 */
	function admin($page = null, $values = null) {
		if (is_null($values)) {
			$values = $this->admin_theme;
		}
		$this->set($values);
		
		if (!is_null($page)) {
			$this->page($page);
		}
		
		return $this;
	}

	/**
	 * page ( $page = null )
	 * 
	 * Sets the page to use. After setting this a page will NOT be automatically loaded based on uri.
	 * 
	 * @access public
	 * @param string $page (default: null) page path
	 * @return Themes
	 */
	function page($page = null) {
		$this->page = $page;
		return $this;
	}
	
	/**
	 * theme ( $theme = null )
	 * 
	 * Sets the theme to use. Useful when you want to set a different theme than default for specific pages.
	 * 
	 * @access public
	 * @param string $theme (default: null)
	 * @return Themes
	 */
	function theme($theme = null) {
		$this->theme = $theme;
		return $this;
	}

	/**
	 * set ( $values = array() )
	 * 
	 * Sets the values of array passed in. Works with page, master, theme, sep, etc. $this->*
	 * 
	 * @access public
	 * @param array $values (default: array())
	 * @return Themes
	 */
	function set($values = array()) {
		foreach ($values as $k => $v) {
			if ($k == 'themes_root') {
				$this->set_themes_root($v);
			}
			else if ($k == 'views_root') {
				$this->set_views_root($v);
			}
			else {
				$this->$k = $v;
			}
		}
		return $this;
	}

 	/**
	 * set_folder ( $values = array() )
	 * 
	 * Sets the folders from array passed in.
	 * 
	 * @access public
	 * @param array $values (default: array())
	 * @return Themes
	 */
	function set_folder($values = array()) {
		foreach ($values as $k => $v) {
			$this->folders[$k] = $v;
		}
		return $this;
	}
	
	/**
	 * set_views_root ( $root = '' )
	 * 
	 * Sets the root of the views folder
	 * 
	 * @access public
	 * @param string $root (default: '')
	 * @return Themes
	 */
	function set_views_root($root = '') {
		$this->views_root = ($root == '') ? $root : trim($root, '/') . '/';
		$this->ci->load->_ci_view_path = $this->views_root . $this->folders['views']. '/';
		return $this;
	}
	
	/**
	 * set_themes_root ( $root = '' )
	 * 
	 * Sets the root of the themes folder
	 * 
	 * @access public
	 * @param string $root (default: '')
	 * @return Themes
	 */
	function set_themes_root($root = '') {
		$this->themes_root = ($root == '') ? $root : trim($root, '/') . '/';
		return $this;
	}
	
	/**
	 * set_root ( $root = '' )
	 * 
	 * Sets the root of the views and themes folder
	 * 
	 * @access public
	 * @param string $root (default: '')
	 * @return Themes
	 */
	function set_root($root = '') {
		$this->set_views_root($root);
		$this->set_themes_root($root);
		return $this;
	}

	/**
	 * css ( $file = '', $media = 'screen', $attributes = '' )
	 * 
	 * echo a link tag for stylesheets
	 * 
	 * @access public
	 * @param string $file (default: '') file path
	 * @param string $media (default: 'screen') media='$media'
	 * @param string $attributes (default: '') additional attributes
	 * @return Themes
	 */
	function css($file = '', $media = 'screen', $attributes = '') {
		if (substr($file, 0, 1) != '/') {
			$file = '/' . $this->themes_root . $this->folders['themes'] . '/' . $this->theme . '/' . $this->folders['css'] . '/' . $file;
		}
		echo "\t<link rel=\"stylesheet\" type=\"text/css\" href=\"$file\" media=\"$media\" $attributes/>\n";
		return $this;
	}

	/**
	 * js ( $file = '', $inline = false )
	 * 
	 * echo a script tag for javascript
	 * 
	 * @access public
	 * @param string $file (default: '') file path, if starts with a / will use full url instead
	 * @param bool $inline (default: false) display inline if writing acual javascript
	 * @return Themes
	 */
	function js($file = '', $inline = false) {
		if (substr($file, 0, 1) != '/' && !$inline) {
			$file = '/' . $this->themes_root . $this->folders['themes'] . '/' . $this->theme . '/' . $this->folders['javascript'] . '/' . $file;
		}
		if ($inline) {
			echo "\t<script type=\"text/javascript\">\n\t$file\n\t</script>\n";
		}
		else {
			echo "\t<script type=\"text/javascript\" src=\"$file\"></script>\n";
		}
		return $this;
	}

	/**
	 * meta ( $name = '', $content = '', $extras = '' )
	 * 
	 * echo a meta tag with passed in values
	 * 
	 * @access public
	 * @param string $name (default: '') name='$name'
	 * @param string $content (default: '') content='$content'
	 * @param string $extras (default: '') extras to add at the end of the tag
	 * @return Themes
	 */
	function meta($name = '', $content = '', $extras = '') {
		echo "\t<meta name=\"$name\" content=\"$content\" $extras/>\n";
		return $this;
	}
	
	/**
	 * meta_http ( $name = '', $content = '', $extras = '' )
	 * 
	 * echo a meta http-equiv tag with passed in values
	 * 
	 * @access public
	 * @param string $name (default: '')
	 * @param string $content (default: '')
	 * @param string $extras (default: '')
	 * @return void
	 */
	function meta_http($name = '', $content = '', $extras = '') {
		echo "\t<meta http-equiv=\"$name\" content=\"$content\" $extras/>\n";
		return $this;
	}

	/**
	 * block ( $name = null, $data = array() )
	 * 
	 * Loads a content block from views folder / blocks folder /
	 * 
	 * @access public
	 * @param string $name (default: null) name of content block
	 * @param array $data (default: array()) data to extract()
	 * @return Themes
	 */
	function block($name = null, $data = array()) {
		if (substr($name, 0, 1) == '/') {
			$full_path = substr($name, 1);
			if (file_exists($full_path . EXT)) {
				$name = explode('/', $name);
				$name = end($name);
				$_ci_view_path = $this->ci->load->_ci_view_path;
				$this->ci->load->_ci_view_path = str_replace($name, '', $full_path);
				$this->ci->load->view($name . EXT, $data);
				$this->ci->load->_ci_view_path = $_ci_view_path;
			}
			else {
				show_error('[ ' . $full_path . EXT . ' ] can not be found.');
			}
		}
		elseif (file_exists($this->ci->load->_ci_view_path . $this->folders['blocks'] . '/' . $name . EXT)) {
			$this->ci->load->view($this->folders['blocks'] . '/' . $name . EXT, $data);
		}
		else {
			show_error('[ ' . $this->ci->load->_ci_view_path . $this->folders['blocks'] . '/' . $name . EXT . ' ] can not be found.');
		}
		return $this;
	}

	/**
	 * load ( $data = array(), $naming_limit = 2 )
	 * 
	 * Loads the final page based on the settings in $this
	 * 
	 * @access public
	 * @param array $data (default: array()) pass in data to extract()
	 * @param int $naming_limit (default: 2) used to cap the auto naming from uri
	 * @return void
	 */
	function load($data = array(), $naming_limit = 2) {
		// get the page view based on uri
		if (is_null($this->page)) {
			switch ($this->ci->uri->total_segments()) {
				// if at root uri, use current value
				case 0:
					$this->page = 'index';
					break;
				// if 1 uri segment, use it
				case 1:
					$this->page = $this->ci->uri->segment(1) . (($this->sep == '/') ? '/index' : '');
					break;
				// if more than 1 uri segment use name($this->sep)subname til $naming_limit
				default:
					for ($i = 1; $i <= $naming_limit; $i++) {
						if ($i == 1) {
							$this->page = $this->ci->uri->segment($i);
						}
						else {
							$this->page .= $this->sep . $this->ci->uri->segment($i);
						}
				}
			}
		}

		// load the master or error out
		if (substr($this->master, 0, 1) == '/') {
			$full_path = substr($this->master, 1);
			if (file_exists($full_path . EXT)) {
				$master = explode('/', $this->master);
				$master = end($master);
				$_ci_view_path = $this->ci->load->_ci_view_path;
				$this->ci->load->_ci_view_path = str_replace($master, '', $full_path);
				$this->contents = $this->ci->load->view($master . EXT, $data, true);
				$this->ci->load->_ci_view_path = $_ci_view_path;
			}
			else {
				show_error('[ ' . $full_path . EXT . ' ] could not be found.');
			}
		}
		elseif (file_exists($this->ci->load->_ci_view_path . $this->folders['masters'] . '/' . $this->master . EXT)) {
			$this->contents = $this->ci->load->view($this->folders['masters'] . '/' . $this->master . EXT, $data, true);
		}
		else {
			show_error('[ ' . $this->ci->load->_ci_view_path . $this->folders['masters'] . '/' . $this->master . EXT . ' ] could not be found.');
		}

		// load the page or error out
		if (substr($this->page, 0, 1) == '/') {
			$full_path = substr($this->page, 1);
			if (file_exists($full_path . EXT)) {
				$page = explode('/', $this->page);
				$page = end($page);
				$_ci_view_path = $this->ci->load->_ci_view_path;
				$this->ci->load->_ci_view_path = str_replace($page, '', $full_path);
				$this->contents = str_replace($this->content($this->content_tag), $this->ci->load->view($page . EXT, array(), true) . "\n", $this->contents);
				$this->ci->load->_ci_view_path = $_ci_view_path;
			}
			else {
				show_error('[ ' . $full_path . EXT . ' ] could not be found.');
			}
		}
		elseif (file_exists($this->ci->load->_ci_view_path . $this->folders['pages'] . '/' . $this->page . EXT)) {
			$this->contents = str_replace($this->content($this->content_tag), $this->ci->load->view($this->folders['pages'] . '/' . $this->page . EXT, array(), true) . "\n", $this->contents);
		}
		else {
			show_error('[ ' . $this->ci->load->_ci_view_path . $this->folders['pages'] . '/' . $this->page . EXT . ' ] could not be found.');
		}

		// output the page
		$this->ci->output->set_output($this->contents);
	}

	/**
	 * content ( $tag = null )
	 * 
	 * Calls final output and echos to browser. Encrypts tag with sha1() to help prevent accidental multiple tag replacements.
	 * 
	 * @access public
	 * @param mixed $tag (default: null) if null returns (find tag to replace), else echo (out tag in template)
	 * @return void
	 */
	function content($tag = null) {
		if (!is_null($tag)) {
			return sha1($tag);
		}
		else {
			echo sha1($this->content_tag);
		}
	}


} /* Themes */

/* End of file Themes.php */
/* Location: app/libraries */